package com.gxa.jjty.phy.service.impl;


import com.gxa.jjty.core.common.ExceptionCode;
import com.gxa.jjty.core.exception.BusinessException;
import com.gxa.jjty.core.pojo.PhyUser;
import com.gxa.jjty.core.service.impl.BaseServiceImpl;
import com.gxa.jjty.core.util.JsonUtil;
import com.gxa.jjty.core.util.MD5Util;
import com.gxa.jjty.core.util.StringUtil;
import com.gxa.jjty.phy.mapper.PhyUserMapper;
import com.gxa.jjty.phy.service.PhyUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;


import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName PhyUserServiceImpl
 * @Author: ws
 * @date 2021/12/2 14:21
 */
@Service("phyUserService")
@Transactional(rollbackFor = Throwable.class)
public class PhyUserServiceImpl extends BaseServiceImpl<PhyUser> implements PhyUserService {

    @Autowired
    private PhyUserMapper phyUserMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 在用户注册时记录远程ip地址，用request的 remote相关方法
     * service中就需要得到HttpServletRequest对象
     * 通过注入方法: 1.@Autowired
     * 2.@Resource 必须保持命名规范
     * 并在request调用方法时装配
     * 在spring和springboot中可直接对request实现注入/装配
     */
    @Autowired
    private HttpServletRequest request;

    //设置token前缀,防止被抓包
    public static final String SECREAT = "!@YYDS@YY#D#sL#";

    @Override
    public Map login(String userName, String password) throws BusinessException {

        // 查询用户是否存在
        PhyUser phyUser = new PhyUser();
        phyUser.setUserName(userName);
        List<PhyUser> select = phyUserMapper.select(phyUser);

        // 用户不存在
        if (select.size() <= 0) {
            throw new BusinessException(ExceptionCode.DELETE_DEFEATED);
        }

        PhyUser findUser = select.get(0);

        // 用户存在，但状态为0
        if (!findUser.getState()) {
            throw new BusinessException(ExceptionCode.ERROR_USER_STATE);
        }

        // 用户存在,校验密码
        if (!MD5Util.encode(password).equals(findUser.getPassword())) {
            throw new BusinessException(ExceptionCode.LOGIN_FAILED);
        }

        //如果用户存在,获取上次的token,如果不为空移除redis中上一次的登录信息
        String expireToken = findUser.getToken();
        if (expireToken != null) {
            redisTemplate.delete(SECREAT + expireToken);
        }

        // 用户存在且校验通过
        // 生成token
        String token = UUID.randomUUID().toString().replace("-", "");

        // 处理登录
        // 设置token
        findUser.setToken(token);

        // 更新信息
        phyUserMapper.updateByPrimaryKeySelective(findUser);

        // redis添加token信息和过期时间
        // key: token
        // value: 用户信息(json）
        // 过期时间: pc端2小时  手机端app 1个月,手机端h5 2小时
        redisTemplate.opsForValue().set(SECREAT + token, JsonUtil.objectToString(findUser), 15, TimeUnit.DAYS);


        Map<String, Object> result = new HashMap<>();
        result.put("token", token);
        result.put("user", findUser);
        return result;
    }

    @Override
    public Map loginByPhone(String phone, String code) throws BusinessException {

        //一键登录
        //1.获取redis服务器存储的验证码
        String redisCode = null;
        Object o = redisTemplate.opsForValue().get(SmsServiceImpl.LOGIN_SMS + phone);
        if (o == null) {
            throw new BusinessException(ExceptionCode.WRONG_CODE);
        }
        redisCode = o.toString();

        //验证码失效的判断,如果为空则抛出异常
        if (StringUtil.isEmpty(redisCode)) {
            throw new BusinessException(ExceptionCode.WRONG_CODE);
        }

        // 对验证码做校验, 如果不一致则抛出异常
        if (!redisCode.equals(code)) {
            throw new BusinessException(ExceptionCode.WRONG_CODE_FAILED);
        }

        // 删除验证码,防止验证码多次使用
        redisTemplate.delete(SmsServiceImpl.LOGIN_SMS + phone);

        //一键登录
        //校验完成, 从mysql数据库中查找用户信息
        //通过手机号查询用户是否存在
        PhyUser phyUser = new PhyUser();
        phyUser.setPhone(phone);
        List<PhyUser> select = phyUserMapper.select(phyUser);

        // 用户不存在
        if (select.size() <= 0) {
            throw new BusinessException(ExceptionCode.NOT_PHONE);
        }

        PhyUser findUser = select.get(0);

        System.out.println(findUser);

        //如果用户存在,获取上次的token,如果不为空移除redis中上一次的登录信息
        String expireToken = findUser.getToken();
        if (expireToken != null) {
            redisTemplate.delete(SECREAT + expireToken);
        }


//        一键注册
//        if (findUser == null){
//            findUser = new PhyUser();
//
//            // 注册时才需要的字段
//            findUser.setUserName("用户"+phone);
//            findUser.setStatus(1);
//            findUser.setLoginType(1);
//            findUser.setPhone(phone);
//
//        }

        //如果用户存在, 但状态不为1,表示冻结状态, 抛出异常
        if (!findUser.getState()) {
            throw new BusinessException(ExceptionCode.ERROR_USER_STATE);
        }

//        //如果用户存在,获取上次的token,如果不为空移除redis中上一次的登录信息
//        expireToken = findUser.getToken();
//        if (expireToken != null) {
//            redisTemplate.delete(SECREAT + expireToken);
//        }

        //如果用户执行登录流程，同样需要更新ip/token/最近的登录时间
        // request.getRemoteAddr()： 获得ip地址
//        findUser.setIpAddress(request.getRemoteAddr());
//        findUser.setLastLoginTime(new Date());

        //生成token，存储登录信息(json),利用处理后的UUID
        String token = UUID.randomUUID().toString().replace("-", "");

        //处理登录
        // 设置token
        findUser.setToken(token);

        //将设置好的用户信息执行添加/更新
        phyUserMapper.updateByPrimaryKeySelective(findUser);

        // redis添加token信息和过期时间
        // key: token
        // value: 用户信息(json）
        // 过期时间: pc端2小时  手机端app 1个月,手机端h5 2小时
        redisTemplate.opsForValue().set(SECREAT + token, JsonUtil.objectToString(findUser), 15, TimeUnit.DAYS);

        Map<String, Object> result = new HashMap<>(2);
        result.put("token", token);
        result.put("user", findUser);

        return result;
    }

    @Override
    public void changePassword(Long id, String password, String newPassword) throws BusinessException {

        if(id == null){
            throw new BusinessException(ExceptionCode.LOCK_FAILED);
        }

        PhyUser phyUser = phyUserMapper.selectByPrimaryKey(id);

        if (phyUser == null) {
            throw new BusinessException(ExceptionCode.DELETE_DEFEATED);
        }

        if (!phyUser.getPassword().equals(MD5Util.encode(password))) {
            throw new BusinessException(ExceptionCode.ERROR_PWD);
        }

        phyUser.setPassword(MD5Util.encode(newPassword));
        phyUserMapper.updateByPrimaryKeySelective(phyUser);
    }

    @Override
    public void logout(String token) {

        // 校验redis是否存在的token
        Object o = redisTemplate.opsForValue().get(SECREAT + token);

        // 存在才能删除
        if (o != null) {
            Boolean delete = redisTemplate.delete(SECREAT + token);
            System.out.println(delete);
        }

    }

    @Override
    public List<PhyUser> selectByDesc() {
        Example example = new Example(PhyUser.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andLike("serverState","空闲");
        example.orderBy("distance");
        List<PhyUser> phyUsers = phyUserMapper.selectByExample(example);
        return phyUsers;
    }
}
